/**
 * 
 */
package GUI;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import Cards.Card;
import Square.Negotiable;
import Utils.Utils;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JDialog;
import javax.swing.JFrame;

/**
 * @author Avia Tam
 * @author Assaf Miron
 *
 */
@SuppressWarnings("serial")
public class PopUpDialog extends JDialog implements PropertyChangeListener {

    private Negotiable asset;
    private Card card;
    private String message;
    private Integer timeOut;
    private JOptionPane optionPane;
    private Integer userResponse;

    public enum eDialog {

	BUY("buy", JOptionPane.YES_OPTION), CANCEL("cancel", JOptionPane.NO_OPTION), DOIT("Do it", JOptionPane.OK_OPTION);
	private String sValue;
	private Integer iValue;

	private eDialog(String s, Integer v) {
	    this.sValue = s;
	    this.iValue = v;
	}

	public final String getText() {
	    return this.sValue;
	}

	public final Integer getValue() {
	    return this.iValue;
	}
    };

    private PopUpDialog(JFrame parent) {
	super(parent);
	// Set the Look and Feel of the Dialog
	Utils.setLookAndFeel();
	if(parent != null){
	    // Position in Center Parent
	    Utils.posCenterScreen(parent.getWidth(), parent.getHeight());
	}
	// Set the Default Close Action to Nothing
	setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
	// Add window Listener
	addWindowListener(new WindowAdapter() {

	    @Override
	    public void windowClosing(WindowEvent we) {
		closeDialog();
	    }
	});
    }

    /**
     * Closes the Dialog
     */
    public void closeDialog(){
	this.setVisible(false);
	this.dispose();
    }

    /**
     * Closes the Dialog with a Default Options Response
     * @param defResponse The Default JOptions Action
     * @see JOptionPane
     */
    public void closeDialog(Integer defResponse){
	optionPane.setValue(defResponse);
	this.setVisible(false);
    }

    /**
     * Construct a New Popup Dialog
     * @param parent The Parent Frame of this Dialog
     * @param asset The Asset to show details on
     */
    public PopUpDialog(JFrame parent, Negotiable asset) {
	this(parent);
	this.asset = asset;
    }

    /**
     * Construct a New Popup Dialog
     * @param parent The Parent Frame of this Dialog
     * @param card The Card to Display
     */
    public PopUpDialog(JFrame parent, Card card) {
	this(parent);
	this.card = card;
    }

    /**
     * Construct a New Popup Dialog
     * @param parent The Parent Frame of this Dialog
     * @param message The Message to Show
     */
    public PopUpDialog(JFrame parent, String message) {
	this(parent);
	this.message = message;
    }

    /**
     * Construct a New Popup Dialog
     * @param parent The Parent Frame of this Dialog
     * @param asset The asset to Display
     * @param timer The Number of Seconds this Dialog should Appear
     */
    public PopUpDialog(JFrame parent, Negotiable asset, Integer timer) {
	this(parent);
	this.asset = asset;
	// Set the Timeout Task
	setTimeout(timer, JOptionPane.NO_OPTION);
    }

    /**
     * Construct a New Popup Dialog
     * @param parent The Parent Frame of this Dialog
     * @param card The Card To Display
     * @param timer The Number of Seconds this Dialog should Appear
     */
    public PopUpDialog(JFrame parent, Card card, Integer timer) {
	this(parent);
	this.card = card;
	// Set the Timeout Task
	setTimeout(timer, JOptionPane.OK_OPTION);
    }

    /**
     * Construct a New Popup Dialog
     * @param parent The Parent Frame of this Dialog
     * @param message The Message to Show
     * @param timer The Number of Seconds this Dialog should Appear
     */
    public PopUpDialog(JFrame parent, String message, Integer timer) {
	this(parent);
	this.message = message;
	// Set the Timeout Task
	setTimeout(timer, JOptionPane.CLOSED_OPTION);
    }

    /**
     * Show a Buying Asset Dialog
     * @return The User Responce
     */
    public Boolean showBuyDialog() {
	optionPane = new JOptionPane(
		asset.getDetails(),
		JOptionPane.QUESTION_MESSAGE,
		JOptionPane.YES_NO_OPTION,
		Utils.getImageIcon("/icon.png"),
		new String[]{"Buy", "Cancel"},
		"Buy");

	// Prepare the Dialog and Show it
	prepDialog("Do you want to Buy " + asset.getName());

	// Wait fo the User to Respond
	while (optionPane.getValue().equals(JOptionPane.UNINITIALIZED_VALUE)) {
	    try {
		Thread.sleep(100);
	    } catch (InterruptedException ex) {
		Logger.getLogger(PopUpDialog.class.getName()).log(Level.SEVERE, null, ex);
	    }
	}

	// Get the User Response
	userResponse = ((Integer) optionPane.getValue());

	// We are Finished - Close the Dialog
	closeDialog();

	// Return the User Response
	return getUserResponse(userResponse);
    }

    /**
     * Show a Surprise Card Dialog
     * @return True (After the player clicked OK)
     */
    public Boolean showSurpriseDialog() {
	String Desc;
	if (card != null) {
	    // Get the Card Description Message
	    Desc = Utils.StringToHTML(card.getDescription());
	} else {
	    // Get the Message instead of the Card
	    Desc = Utils.StringToHTML(message);
	}
	optionPane = new JOptionPane(
		Desc,
		JOptionPane.QUESTION_MESSAGE,
		JOptionPane.OK_OPTION,
		Utils.getImageIcon("/surprise.png"),
		new String[]{"Do it"},
		"Do it");

	// Prepare the Dialog and Show it
	prepDialog("You got a Surprise Card!");

	// Wait fo the User to Respond
	while (optionPane.getValue().equals(JOptionPane.UNINITIALIZED_VALUE)) {
	    try {
		Thread.sleep(100);
	    } catch (InterruptedException ex) {
		Logger.getLogger(PopUpDialog.class.getName()).log(Level.SEVERE, null, ex);
	    }
	}
	// Get the User Response
	userResponse = ((Integer) optionPane.getValue());

	// We are Finished - Close the Dialog
	closeDialog();

	// Return the User Response
	return getUserResponse(userResponse);
    }

    /**
     * Show a Warning Card Dialog
     * @return True (After the player clicked OK)
     */
    public Boolean showWarningDialog() {
	String Desc;
	if (card != null) {
	    // Get the Card Description Message
	    Desc = Utils.StringToHTML(card.getDescription());
	} else {
	    // Get the Message instead of the Card
	    Desc = Utils.StringToHTML(message);
	}
	optionPane = new JOptionPane(
		Desc,
		JOptionPane.QUESTION_MESSAGE,
		JOptionPane.OK_OPTION,
		Utils.getImageIcon("/warning.png"),
		new String[]{"Do it"},
		"Do it");

	// Prepare the Dialog and Show it
	prepDialog("You got a Warning Card!");

	// Wait fo the User to Respond
	while (optionPane.getValue().equals(JOptionPane.UNINITIALIZED_VALUE)) {
	    try {
		Thread.sleep(100);
	    } catch (InterruptedException ex) {
		Logger.getLogger(PopUpDialog.class.getName()).log(Level.SEVERE, null, ex);
	    }
	}
	// Get the User Response
	userResponse = ((Integer) optionPane.getValue());

	// We are Finished - Close the Dialog
	closeDialog();

	// Return the User Response
	return getUserResponse(userResponse);
    }

    /**
     * Show a Dialog Message
     * @param panel The Parent Panel
     */
    public void showMessage() {
	optionPane = new JOptionPane(message, JOptionPane.INFORMATION_MESSAGE);

	// Prepare the Dialog and Show it
	prepDialog("Monopoly Game Message");

	// Wait fo the User to Respond
	while (optionPane.getValue().equals(JOptionPane.UNINITIALIZED_VALUE)) {
	    try {
		Thread.sleep(100);
	    } catch (InterruptedException ex) {
		Logger.getLogger(PopUpDialog.class.getName()).log(Level.SEVERE, null, ex);
	    }
	}

	// We are Finished - Close the Dialog
	closeDialog();
    }

    /**
     * Show an Error Dialog Message
     * @param panel The Parent Panel
     */
    public void showErrorMessage(){
		optionPane = new JOptionPane(message, JOptionPane.ERROR_MESSAGE);

	// Prepare the Dialog and Show it
	prepDialog("Monopoly Game Error");

	// Wait fo the User to Respond
	while (optionPane.getValue().equals(JOptionPane.UNINITIALIZED_VALUE)) {
	    try {
		Thread.sleep(100);
	    } catch (InterruptedException ex) {
		Logger.getLogger(PopUpDialog.class.getName()).log(Level.SEVERE, null, ex);
	    }
	}

	// We are Finished - Close the Dialog
	closeDialog();
	 
    }

    /**
     * This is a Helper function for displaying a question to the Player and returning its answer
     * @param diagQuestion The Question to Display to the Player
     * @return The Players' Answer (Yes - True, No - False)
     */
    public Boolean showPlayerDialog() {
	// Show a Confirm Dialog and Get the User Answer
	optionPane = new JOptionPane(
		message,
		JOptionPane.QUESTION_MESSAGE,
		JOptionPane.YES_NO_OPTION);

	// Prepare the Dialog and Show it
	prepDialog("Java Monopoly Question");

	// Wait fo the User to Respond
	while (optionPane.getValue().equals(JOptionPane.UNINITIALIZED_VALUE)) {
	    try {
		Thread.sleep(100);
	    } catch (InterruptedException ex) {
		Logger.getLogger(PopUpDialog.class.getName()).log(Level.SEVERE, null, ex);
	    }
	}

	// Get the User Response
	userResponse = ((Integer) optionPane.getValue());

	// We are Finished - Close the Dialog
	closeDialog();

	// Return the correct value
	return getUserResponse(userResponse);
    }

    /**
     * Create a New Timer to Activate on Timeout
     * @param timeOutSeconds The Time in Seconds
     */
    private void setTimeout(Integer timeOutSeconds, Integer defOptions) {
	timeOut = timeOutSeconds;
	Timer hideDialogTimer = new Timer("Hide Opend Dialog", true);
	hideDialogTimer.schedule(new HideDialog(this, defOptions), timeOutSeconds * 1000);
    }

    /**
     * Prepares the Dialog with the Options Pane
     * @param options The JOption Pane to Check
     */
    private void prepDialog(String title) {
	// Set the Dialog Title
	setTitle(title);
	// Set the Content of the Dialog
	setContentPane(optionPane);
	// Add a Listener to the Options Pane
	optionPane.addPropertyChangeListener(this);
	// Pack
	this.pack();
	// Position in Center Screen
	setLocationRelativeTo(getParent());
	// Show the Window
	this.setVisible(true);
    }

    /**
     * Gets the User Response from The JOptionPane
     * @param options The JOption Pane to Check
     * @return The User Response
     */
    private Boolean getUserResponse(Integer userResponse) {
	// Check the Response and Return the Value
	if (userResponse == JOptionPane.YES_OPTION || userResponse == JOptionPane.OK_OPTION) {
	    return true;
	} else if (userResponse == JOptionPane.NO_OPTION) {
	    return false;
	}
	// Default
	return false;
    }

    /** This method reacts to state changes in the option pane. */
    public void propertyChange(PropertyChangeEvent e) {
	String prop = e.getPropertyName();

	if (isVisible()
		&& (e.getSource() == optionPane)
		&& (JOptionPane.VALUE_PROPERTY.equals(prop)
		|| JOptionPane.INPUT_VALUE_PROPERTY.equals(prop))) {
	    Object value = optionPane.getValue();

	    if (value == JOptionPane.UNINITIALIZED_VALUE) {
		//ignore reset
		return;
	    }

	    try {
		if (((String) optionPane.getValue()).equalsIgnoreCase(eDialog.BUY.getText())) {
		    optionPane.setValue(eDialog.BUY.getValue());
		} else if (((String) optionPane.getValue()).equalsIgnoreCase(eDialog.CANCEL.getText())) {
		    optionPane.setValue(eDialog.CANCEL.getValue());
		} else if (((String) optionPane.getValue()).equalsIgnoreCase(eDialog.DOIT.getText())) {
		    optionPane.setValue(eDialog.DOIT.getValue());
		} else if (optionPane.getValue().equals(JOptionPane.CLOSED_OPTION)) {
		    closeDialog();
		}
	    } catch (ClassCastException ex) {

	    }
	}
    }
}

/**
 * Timer Task that Hides a Dialog
 * @author Avia Tam
 * @author Assaf Miron
 *
 */
class HideDialog extends TimerTask {

    PopUpDialog myDialog;
    Integer defResponse;
    /**
     * Initializes the Task with the Options Pane
     * @param options
     */
    public HideDialog(PopUpDialog dialog, Integer defResponse) {
	myDialog = dialog;
	this.defResponse = defResponse;
    }

    @Override
    public void run() {
	myDialog.closeDialog(defResponse);
    }
}
